package com.heima.article.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.ArticleApp;
import com.heima.article.dto.*;
import com.heima.article.entity.ApArticle;
import com.heima.article.entity.ApArticleContent;
import com.heima.article.entity.ApCollection;
import com.heima.article.feign.BehaviorFeign;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.IApArticleContentService;
import com.heima.article.service.IApArticleService;
import com.heima.article.service.IApCollectionService;
import com.heima.article.service.ITemplateService;
import com.heima.common.dto.ResponseResult;
import com.heima.common.dto.User;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.util.AppThreadLocalUtil;
import com.heima.common.util.ArticleThreadLocalUtil;
import com.heima.common.util.RedisConstant;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * <p>
 * 文章信息表，存储已发布的文章 服务实现类
 * </p>
 *
 * @author mcm
 * @since 2022-03-14
 */
@Service
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements IApArticleService {

    @Autowired
    private IApArticleContentService contentService;

    /**
     * 保存文章
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult<Long> saveApArticle(ArticleDto dto) {
        ApArticle article = new ApArticle();
        BeanUtils.copyProperties(dto, article);
        // 判断是否存在id
        if (dto.getId() == null) {
            // 不存在id 新增文章
            article.setCreatedTime(new Date());
            this.save(article);
            // 新增文章内容
            ApArticleContent content = new ApArticleContent();
            content.setArticleId(article.getId());
            content.setContent(dto.getContent());
            contentService.save(content);

            // 生成静态html  需要异步处理
            System.out.println(Thread.currentThread().getName() + " 开始调用生成静态html服务...");
            templateService.createHtml(article, dto.getContent());
            System.out.println(Thread.currentThread().getName() + " 生成静态html调用结束");
            return ResponseResult.okResult(article.getId());
        }
        // 存在id 更新文章
        this.updateById(article);
        // 更新文章内容
        LambdaUpdateWrapper<ApArticleContent> update = new LambdaUpdateWrapper<>();
        update.eq(ApArticleContent::getArticleId, dto.getId());
        update.set(ApArticleContent::getContent, dto.getContent());
        contentService.update(update);
        // todo 更新静态html
        return ResponseResult.okResult(dto.getId());
    }

    @Autowired
    @Lazy
    private ITemplateService templateService;
    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 加载文章列表
     *
     * @param dto
     * @param type 0: 默认首页最新文章  1: 更多文章-下一页
     * @return
     */
    @Override
    public ResponseResult load(ArticleHomeDto dto, int type) {
        //首先从缓存获取热点文章
        if(dto.getLoaddir()==1) {
            Set<String> strings= redisTemplate.opsForZSet().reverseRange(RedisConstant.HOT_ARTICLE , 0, dto.getSize() - 1);
            ArrayList<ArticleApp> articleApps = new ArrayList<>();
            strings.forEach(s->articleApps.add(JSON.parseObject(s,ArticleApp.class)));
            if (articleApps.size() >= dto.getSize()) {
                return ResponseResult.okResult(articleApps);
            }
        }




        // 构建查询条件
        LambdaQueryWrapper<ApArticle> query = new LambdaQueryWrapper<>();
        // 如果频道id不为0 添加频道查询条件
        if (dto.getChannelId() != 0) {
            query.eq(ApArticle::getChannelId, dto.getChannelId());
        }
        // 如果类型是0 加载最新文章 添加查询条件:发布时间大于页面传递的最大时间
        if (type == 0) {
            query.gt(ApArticle::getPublishTime, dto.getMaxTime());
        }
        // 如果类型为1 加载下一页  添加查询条件:发布时间小于页面传递的最小时间
        if (type == 1) {
            query.lt(ApArticle::getPublishTime, dto.getMinTime());
        }
        // 已下架和已删除的文章需要排除
        query.eq(ApArticle::getIsDelete, false);
        query.eq(ApArticle::getIsDown, false);
        // 文章列表按照发布时间倒序排列
        query.orderByDesc(ApArticle::getPublishTime);
        IPage<ApArticle> page = new Page<>(1, dto.getSize());
        IPage<ApArticle> iPage = this.page(page, query);
        return ResponseResult.okResult(iPage.getRecords());
    }

    @Override
    public ResponseResult loadArticleInfo(ArticleInfoDto dto) {
        // 根据id查询文章表和文章内容表
        ApArticle apArticle = this.getById(dto.getArticleId());
        LambdaQueryWrapper<ApArticleContent> query = new LambdaQueryWrapper<>();
        query.eq(ApArticleContent::getArticleId, dto.getArticleId());
        ApArticleContent articleContent = contentService.getOne(query);
        // 构建响应对象
        Map<String, Object> map = new HashMap<>();
        map.put("config", apArticle);
        map.put("content", articleContent);
        return ResponseResult.okResult(map);
    }

    @Autowired
    private BehaviorFeign behaviorFeign;

    @Autowired
    private IApCollectionService apCollectionService;

    /**
     * 记录当前登录人收藏的文章
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveCollection(CollectionBehaviorDto dto) {
        // 滤空判断
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 获取本地线程内user对象
        User user = ArticleThreadLocalUtil.get();
        // 构建EntryDto
        EntryDto entryDto = new EntryDto();
        if (user != null) {
            entryDto.setUserId(user.getUserId());
        }
        if (!StringUtils.isEmpty(dto.getEquipmentId())) {
            entryDto.setEquipmentId(dto.getEquipmentId());
        }

        ApBehaviorEntry apBehaviorEntry = null;

        // 调用feign远程获取entry实体
        ResponseResult<ApBehaviorEntry> responseResult = behaviorFeign.getEntry(entryDto);
        if (responseResult.getCode().equals(AppHttpCodeEnum.SUCCESS.getCode())) {
            apBehaviorEntry = responseResult.getData();
        }
        if (apBehaviorEntry != null) {
            // 构造查询条件
            LambdaQueryWrapper<ApCollection> query = new LambdaQueryWrapper<>();
            query.eq(ApCollection::getArticleId, dto.getArticleId())
                    .eq(ApCollection::getEntryId, apBehaviorEntry.getId());
            // 查询是否已经有过收藏记录
            ApCollection one = apCollectionService.getOne(query);
            // 判断操作类型
            if (dto.getOperation() == 1) {
                // 删除
                apCollectionService.remove(query);
            } else { // 新增
                // 如果没有，新增收藏记录
                if (one == null) {
                    one = new ApCollection();
                    one.setEntryId(apBehaviorEntry.getId());
                    one.setCollectionTime(new Date());
                    one.setArticleId(dto.getArticleId());
                    // 保存
                    apCollectionService.save(one);
                }
            }
        }
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult loadArticleBehavior(ArticleInfoDtoV2 dto) {

        Integer userId = ArticleThreadLocalUtil.get().getUserId();
        dto.setUserId(userId);
        LambdaQueryWrapper<ApCollection> queryWrapper = new LambdaQueryWrapper<>();
        //通过userid调用行为服务获取对应的参数
        ResponseResult responseResult = behaviorFeign.handleBehavior(dto);
        //获取dto对象
       Map data = (Map) responseResult.getData();
        ArticleInfoBehaviorDto articleInfoBehaviorDto = BeanUtil.mapToBean(data, ArticleInfoBehaviorDto.class, true, CopyOptions.create(null, true, null));
        //获取entryid，接着封装
        queryWrapper.eq(ApCollection::getEntryId, articleInfoBehaviorDto.getEntryId()).eq(ApCollection::getArticleId, dto.getArticleId());
        articleInfoBehaviorDto.setIscollection(apCollectionService.count(queryWrapper) != 0);
        return ResponseResult.okResult(articleInfoBehaviorDto);
    }

}
